// This is unpublished source code. Michah Lerner 2006

package trieMatch.consoleApps;

// Simple non-threaded driver

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;

import trieMatch.Constants;
import trieMatch.keywordMatcher.KMDefinition;
import trieMatch.keywordMatcher.KeyMatch;
import trieMatch.keywordMatcher.ResultFormatter;
import trieMatch.keywordMatcher.Tiers;
import trieMatch.keywordMatcher.TrieMatcher;
import trieMatch.keywordMatcher.KeyMatch.EvalType;
import trieMatch.keywordMatcher.KeyMatch.MatcherActionDefinition;
import trieMatch.util.TOD;

@Deprecated
public class SimpleQuery {

	final int keymatchFile = 0, testInputsfile = 1, outputFile = 2;
	PrintStream outstream;
	static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
	String filler = String.format("%105s | ", "");
	int nominalLength = 92;
	boolean _useDP = false;
	boolean _echo = false; // echo match inputs?
	boolean SHOWALL = false; // show all results, or just show the top result?
	String aggregatorName = Constants.DEFAULT_AGGREGATOR_NAME;
	String aggregatorParm = Constants.DEFAULT_AGGREGATOR_PARM;

	MatcherActionDefinition resultRequest = MatcherActionDefinition.longest;
	String kmFilename, queryFilename, outputName;
	EvalType evalType;
	static int numTestcols = 2;
	static int testQueryCol = 1;
	static int testResponseCol = 0;
	boolean usesSymbology = false;
	boolean echo;
	ResultFormatter resultFormatter = new ResultFormatter();

	public static void main(final String[] args) {
		System.out.println(TOD.now() + ": EXECUTION BEGINS");
		final SimpleQuery query = new SimpleQuery();
		long tNs;
		final long tCalib = calibrate();

		final String[] sampleArgs = new String[] { "-top", "searchKeys.004.km", "-" };

		final LocalStore localStore = query.new LocalStore(args.length == 0
				? sampleArgs
				: args);

		final String[] sampleQueries = new String[] {
				"Tips on making money in the market right now, with Linda Duessel, equity market strategist at Federated Investors",
				"Robert Horrocks, head of research at Mirae Asset Global Investment Management tells Jerry Lou, China strategist at Morgan Stanley, CNBC's Martin Soong and Emily Chan he is bullish on Hong Kong property.",
				"Market Maven with Ted Parrish, Co-Portfolio Manager, Henssler Equity Fund",
				"Stock picks with Jim Jubak, Senior Markets Editor, CNBC.com on MSN",
				"Morgan Stanley's CEO John Mack will provide testimony in Pequot Capital case, with Charlie Gasparino, Reporter, CNBC Business News",
				"The energy markets are dealing with a major storm, with oil tycoon, Boone Pickens; Steve Roukis, Matrix Asset Advisors managing director/senior portfolio manager; Phil Flynn, Alaron Trading vice president/senior market analyst; Ben Lichtenstein, TradersAudio.com president and CNBC's Becky Quick",
				"Peter Harbison of the Centre for Asia Pacific Aviation takes a pulse check on the airline sector, and how the threat of another terror attack could affect air travel.",
				"The Chinese government is planning to introduce curbs to auto policies in order to cool an overheating economy. CNBC's Cheng Lei with that and other big movers in China.",
				"Unless the Federal Reserve changes its stance, the market should go higher, with Dennis Gartman, The Gartman Letter, and the Fast Money traders.",
				"Mark Hulbert Columnist Dow Jones MarketWatch and Hulbert Financial Digest Editor takes a look at the Dow's tech stocks",
				"KPN posted a better than expected results for Q2 boosted by its mobile telephones operations. CNBC speaks to Marcel Smits, CFO about the group's new brands." };
		for (final String qstring : sampleQueries) {
			tNs = System.nanoTime();
			final List<String> results = localStore.runMatch(qstring);
			tNs = tNs - System.nanoTime() - tCalib;
			System.out.printf("time: %14.12f ns ", tNs / 1E9);
			for (final String result : results) {
				System.out.println(qstring + " // " + result);
			}
		}
		System.out.println(TOD.now() + ": EXECUTION COMPLETE");
		System.exit(0);
	}

	public class LocalStore {
		KeyMatch kmPrimary;
		TrieMatcher trieMatcher;
		String[] queryFilenames;

		LocalStore(final String[] args) {
			processArgs(args);
			Tiers.mapFactoryInstance = resultRequest.getMapFactory();
			TrieMatcher.setAggregator(aggregatorName, aggregatorParm);
			System.out.println(TOD.now() + ": Start reading keymatches from " + kmFilename);
			try {
				kmPrimary = new KeyMatch(kmFilename);
			} catch (final IOException e) {
				e.printStackTrace();
			}
			System.out.println(TOD.now() + ": read " + KeyMatch.symbolToName.size() + " lines.");
			trieMatcher = resultRequest.select(kmPrimary.tiers, kmPrimary.elementIndexer);
		}

		List<String> runMatch(final String... queries) {
			final List<String> res = new ArrayList<String>();
			for (final String query : queries) {
				res.addAll(eval(this, query.trim()));
			}
			return res;
		}
	}

	public static long calibrate() {
		final int numCalls = 100;
		long sumCalib = 0, t0 = 0;
		for (int i = 0; i < 100; i++) {
			t0 = System.nanoTime();
			sumCalib += System.nanoTime() - t0;
		}
		return sumCalib / numCalls;
	}

	public void showStats(final long mtime, final int nQueries) {
		System.out.println(TOD.now() + ": Issued total of " + nQueries + " requests");
		System.out.println(TOD.now() + ": " + "'single'" + " thread;  " + "all" + " queries/batch; " + "one" + " batch generated, "
				+ "one" + " started, " + "one" + " returned, " + "one" + " completed.");
		System.out.println(TOD.now() + ": ::SUMMARY:: " + "queryRate=" + (nQueries / (double) mtime) + " qpms"
				+ ";  queriesProcessed=" + nQueries + ";  showResults=" + (outstream == null
						? "suppressed"
						: "enabled") + ";  timeElapsed=" + mtime + " ms" + ";  timeUtilized=" + mtime + " ms" + ";  _numThreads="
				+ "'one'" + ";  _chunkSize=" + "all" + " queries" + ";  numInputs=" + nQueries + ";  numIter=" + "one"
				+ ";  numThread=" + "'one'" + ";  aggregator=" + aggregatorName + (aggregatorParm != null
						? ("(" + aggregatorParm + ")")
						: "") + ";  searchFlavor=" + resultRequest + ";  keymatchFile=\"" + kmFilename + "\";  queryFile=\""
				+ queryFilename + "\"");
	}

	public List<String> readEval(final LocalStore localStore) {
		System.out.println("?");
		final String queryText = getLine().trim();
		return eval(localStore, queryText);
	}

	public List<String> eval(final LocalStore localStore, final String queryText) {
		final List<KMDefinition> ans = localStore.trieMatcher.findMatch(queryText);
		return resultFormatter.formatResults(localStore.trieMatcher.reduce(ans));
	}

	public String getLine() {
		String s = null;
		try {
			while (!in.ready()) {
				Thread.sleep(100);
			}
			s = in.readLine();
			return s;
		} catch (final Exception e) {
			e.printStackTrace();
		}
		return s;
	}

	static String getQueryPart(final String[] line) {
		if (testQueryCol < line.length) { return line[testQueryCol]; }
		return null;
	}

	static String getResponsePart(final String[] line) {
		if (testResponseCol < line.length) { return line[testResponseCol]; }
		return null;
	}

	public void usage() {
		System.err.println("usage: java -jar file.jar [options] keymatchFilename testinputsFilename [outputFilename]");
		System.err
				.println("       options: -all/-longest/-top/-exp       -echo/-noEcho    -deleteOutputFile  -preExpand  -permuteExpand");
		System.err.println("                -nArg #");
		System.err.println("\n       the -exp gives \"experimental\" prefix matching and supports \"lookahead\".");
		System.err.println("\n       For interactive input use: java -Xmx1540M -jar c:\\mlrus\\kmQ.jar 5000.input $in - -all");
		System.exit(0);
	}

	public void processArgs(final String[] args) {
		boolean deleteOutputfile = false;
		final List<String> filenames = new ArrayList<String>();
		evalType = EvalType.eINP;
		boolean grab_numTestcols = false;
		for (int i = 0; i < args.length; i++) {
			if (args[i].equalsIgnoreCase("-h")) {
				usage();
			} else if (grab_numTestcols) {
				numTestcols = Integer.parseInt(args[i]);
				grab_numTestcols = false;
				System.out.println("Expect " + numTestcols + " of input per test line");
			} else if (args[i].equalsIgnoreCase("-aggName")) {
				aggregatorName = args[++i];
			} else if (args[i].equalsIgnoreCase("-aggParm")) {
				aggregatorParm = args[++i];
			} else if (args[i].equalsIgnoreCase("-all")) {
				resultRequest = MatcherActionDefinition.all;
			} else if (args[i].equalsIgnoreCase("-longest")) {
				resultRequest = MatcherActionDefinition.longest;
			} else if (args[i].equalsIgnoreCase("-top")) {
				resultRequest = MatcherActionDefinition.top;
			} else if (args[i].equalsIgnoreCase("-exp")) {
				resultRequest = MatcherActionDefinition.exp; // EXPERIMENTAL !!
			} else if (args[i].equalsIgnoreCase("-echo")) {
				echo = true;
			} else if (args[i].equalsIgnoreCase("-noEcho")) {
				echo = false;
			} else if (args[i].equalsIgnoreCase("-nArg")) {
				grab_numTestcols = true;
			} else if (args[i].equalsIgnoreCase("-deleteOutputFile")) {
				deleteOutputfile = true;
			} else {
				filenames.add(args[i]);
			}
		}
		filenames.add(null);
		if (filenames.size() < 2) {
			usage();
			System.exit(0);
		}
		kmFilename = filenames.get(keymatchFile);
		queryFilename = filenames.get(testInputsfile);
		outputName = filenames.get(outputFile);
		checkOutputfile(outputName, deleteOutputfile);
		try {
			outstream = (outputName != null)
					? safePrintStream(outputName)
					: null;
		} catch (final FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	public void showArgs() {
		try {
			System.out.println(TOD.now() + ": Keymatches from " + (new File(kmFilename).getCanonicalPath()));
		} catch (final IOException e) {
			e.printStackTrace();
		}
		System.out.println(TOD.now() + ": Aggregator name " + aggregatorName);
		System.out.println(TOD.now() + ": Aggregator parm " + aggregatorParm);
		System.out.println(TOD.now() + ": Test input from " + queryFilename);
		System.out.println(TOD.now() + ": Results outputs " + (outputName == null
				? "not printed"
				: outputName));
		System.out.println(TOD.now() + ": Results outputs " + resultRequest + " result.");
		System.out.println(TOD.now() + ": Compute evalType " + evalType);
	}

	public void showConfiguration(final KeyMatch kmPrimary, final List<String> queryList) {
		if (echo) {
			System.out.println("Rules:");
			kmPrimary.tiers.printTiers(System.out);
		}
	}

	public String showAndSetFmt(final String query, final String tkr, final int size) {
		outstream.print("\nName:" + query + ".");
		if (tkr != null) {
			outstream.print(" \tSymbol: \"" + tkr + "\".");
		}
		outstream.println(" \tSubquery count: " + size + ".");
		return String.format("%%%ds | dEdit=%%-2d | ", nominalLength - query.length() - (tkr != null
				? tkr.length()
				: 0));
	}

	public static boolean checkOutputfile(final String name, final boolean deletableOutputfile) {
		if (stdFilename(name)) { return false; }
		final File f = new File(name);
		if (!f.exists() || (deletableOutputfile && f.isFile() && f.delete())) { return true; }
		return false;
	}

	static boolean stdFilename(final String filename) {
		return filename == null || filename.length() == 0 || filename.equals("-");
	}

	PrintStream fileFoundHandler(final String s) throws FileNotFoundException {
		throw new FileNotFoundException("File exists: " + s);
	}

	public BufferedReader openInput(final String filename) throws Exception {
		return new BufferedReader((stdFilename(filename)
				? (new InputStreamReader(System.in))
				: (new FileReader(filename))));
	}

	public PrintStream safePrintStream() throws FileNotFoundException {
		return safePrintStream(null);
	}

	public PrintStream safePrintStream(final String filename) throws FileNotFoundException {
		return stdFilename(filename)
				? (new PrintStream(System.out))
				: ((!(new File(filename)).exists())
						? (new PrintStream(filename))
						: fileFoundHandler(filename));
	}
}
